package com.homesoft.runtime.core.loaders;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import com.homesoft.runtime.log.ILog;
import com.homesoft.runtime.log.LogManager;
import com.homesoft.runtime.metadata.modle.RootObjectType;
import com.homesoft.runtime.metadata.modle.RootObjectTypeHelper;

public class DefaultBusinessClassLoader extends BusinessClassLoader {
	
	private static final ILog logger = LogManager.getLogger(DefaultBusinessClassLoader.class);
	private MetadataRuntimeInfoDictionary cache;
	
	@Override
	protected Enumeration<MetadataRuntimeInfo> getAllRuntimeMetadataInfosInternal() {
		return cache.getAllRuntimeMetadataInfos();
	}
	
	public DefaultBusinessClassLoader() {
        cache = new MetadataRuntimeInfoDictionary();
    }
	
	@Override
	protected InputStream getMetadataStreamInternal(String metadataName) {
		return cache.getStream(metadataName);
	}

	@Override
	protected InputStream getMetadataStreamInternal(String metadataName,
			LoadFolder folder) {
		return cache.getStream(metadataName, folder);
	}
	
	@Override
	protected Object getServiceInterfaceTypeInternal(String metadataName) {
		Object serviceInterfaceType = cache.getRuntimeClass(metadataName, MetadataRuntimeType.Interface);
        return serviceInterfaceType;
	}
	
	@Override
	protected Object getEntityRuntimeTypeInternal(String metadataName) {
		MetadataRuntimeInfo info = cache.getRuntimeInfo(metadataName);
		Object type = info.getRuntimeType(MetadataRuntimeType.Entity);
        Object entityType = type != null ? type : info.getRuntimeType(MetadataRuntimeType.Poco);
        return entityType;
	}

	@Override
	protected Object getEnumRuntimeTypeInternal(String metadataName) {
		return cache.getRuntimeClass(metadataName, MetadataRuntimeType.Enumeration);
	}

	@Override
	protected Object getServiceInternal(Object serviceInterfaceType) {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	protected Object getUIControllerInternal(String controllerName) {
		Object controllerType = cache.getRuntimeClass(controllerName, MetadataRuntimeType.UIController);
		
		try {
			if (controllerType != null) {
	        	return Class.forName(controllerType.toString());
	        } else {
	            //logger.WriteTraceLog(LogLevel.Error, String.Format("未找到与[{0}]关联的控制器。", controllerName));
	            return null;
	        }
		} catch (ClassNotFoundException e) {
			return null;
		}
	}
	
	@Override
	protected void clearInternal() {
		if (getClassLoaderIsInitialized())
        {
			setClassLoaderIsInitialized(false);
			cache.clear();
        }
	}
	
	@Override
	protected void initInternal() {
		cache.clear();
        String path = "Assimbly";
        
        if (!"".equals(path)) {
        	return;
        }
        
        //long groupId = logger.BeginWriteTraceLog(LogLevel.Info, "开始初始化Assembly目录下的程序集");
        InitClassLoader(path, LoadFolder.UserFolder);
        //logger.EndWriteTraceLog(groupId, LogLevel.Info, "完成初始化Assembly目录下的程序集");
        setClassLoaderIsInitialized(true);
	}
	
	private void InitClassLoader(String path, LoadFolder folder)
    {
		List<File> files = new ArrayList<File>();
		File lib = new File(path);
		loopFiles(lib, files);
		
		for (File file : files) {
			DoLoadBusinessJar(file, folder);
		}
    }
	
	private void DoLoadBusinessJar(File file, LoadFolder folder) {
		if (file.getName().contains(".biz.")) {
			loadClassJar(file, folder);
		} else if (file.getName().contains(".metadata.")) {
			loadMetadataJar(file, folder);
		}
	}
	
	private void loadClassJar(File file, LoadFolder folder) {
		try {
			JarFile jar = new JarFile(file.getPath());
			Enumeration<JarEntry> e = jar.entries();
			
			URL jarUrl = new URL(file.getPath());
			URLClassLoader loader = new URLClassLoader(new URL[] {jarUrl}, Thread.currentThread().getContextClassLoader());
			
			while (e.hasMoreElements()) {
				JarEntry entry = (JarEntry) e.nextElement();
				String entryName = entry.getName();
				
				if (!entryName.endsWith(".class")) {
					continue;
				}
				
                Class<?> cls = loader.loadClass(entryName);
                
                if (cls.isAnnotationPresent(BusinessAnnotation.class)) {
        			BusinessAnnotation ann = (BusinessAnnotation)cls.getAnnotation(BusinessAnnotation.class);
        			cache.add(ann.MetadataName(), folder, cls.getName(), ann.RuntimeType(), Dependency.getFileDependency(entryName));
        		}
			}
		} catch (IOException e1) {
			// TODO 待实现
		} catch (ClassNotFoundException e2) {
			// TODO 待实现
		}
	}
	
	private void loadMetadataJar(File file, LoadFolder folder) {
		try {
			JarFile jar = new JarFile(file.getPath());
			Enumeration<JarEntry> e = jar.entries();
			
			URL jarUrl = new URL(file.getPath());
			URLClassLoader loader = new URLClassLoader(new URL[] {jarUrl}, Thread.currentThread().getContextClassLoader());
			
			while (e.hasMoreElements()) {
				JarEntry entry = (JarEntry) e.nextElement();
				
				String entryName = entry.getName();
				
				if (!entryName.endsWith(".xml")) {
					continue;
				}
				
				if (!RootObjectTypeHelper.IsMetadataFile(entryName)) {
					continue;
				}
				
                RootObjectType rootObjectType = RootObjectTypeHelper.GetRootObjectType(entryName);
                
                MetadataLoader metaLoader = MetadataLoader.createResourceLoader(loader, entryName);
                metaLoader.setRootObjectType(rootObjectType);

                String metadataName = RootObjectTypeHelper.GetRootObjectFullName(entryName);
                
                cache.add(metadataName, folder, metaLoader, Dependency.getFileDependency(file.getPath()));
			}
		} catch (IOException e) {
			
		}
	}
	
	private static final void loopFiles(File file, List<File> files) {
		if (file.isDirectory()) {
			File[] tmps = file.listFiles();
			
			for (File tmp : tmps) {
				loopFiles(tmp, files);
			}
		} else {
			if (file.getAbsolutePath().endsWith(".jar") || file.getAbsolutePath().endsWith(".zip")) {
				files.add(file);
			}
		}
	}
	
	/*private static final String getClassOrXmlFileName(JarEntry entry) {
	
	String fileName = "";
	String entryName;
	String substr[];
	String tmpName = "";
	
	entryName = entry.getName();
	
	if (entryName.indexOf("META-INF") >= 0 || entryName.indexOf(".class") < 0 || entryName.indexOf(".xml") < 0) {
		return fileName;
	}
	
    substr = entryName.split("/");
    
    for (int i = 0; i < substr.length - 1; i++) {
        if (i > 0) {
            tmpName = tmpName + "/" + substr[i];
        } else {
            tmpName = substr[i];
        }
    }
    
    if (sName.indexOf(".class") < 0)
    {
        sName = sName.substring(0, sName.length() - 1);
    }
}*/
}
